#pragma once
#include <iostream>
#include "../../nclgl/Vector3.h"

struct WavesData
{
	float waveLength;
	float amplitude;
	float speed;
	float k;
	Vector3 direction;
};

__global__ void WavesCubaUpdate(float* height, float* normal, float time, int size, int numWaves, WavesData* wd)
{
	int x = blockIdx.x*blockDim.x + threadIdx.x;
	int y = blockIdx.y*blockDim.y + threadIdx.y;
	
	float PI = 3.141592f;
	int offset = x*size + y;
	if (x >= size || y >= size) return;

	float cx = x*1.0 / size;
	float cy = y*1.0 / size;

	float z = 0;
	float zdx = 0;
	float zdy = 0;

	for (int i = 0; i < numWaves; i++){
		float a = wd[i].amplitude;
		float ax = wd[i].direction.x * cx + wd[i].direction.y*cy;
		float w = 2 * PI / wd[i].waveLength;
		float ang = time * wd[i].speed * 2 * PI / wd[i].waveLength;
		float k = wd[i].k;

		float sinax = sin(ax*w + ang);
		float cosax = cos(ax*w + ang);
		float coeffect = k*w*a*pow((sinax + 1) / 2, k - 1)*cosax;

		z = z + 2 * a * pow(((sinax + 1) / 2), k);
			
		zdx = zdx + wd[i].direction.x * coeffect;		//Binormal (1,0,zdx)
		zdy = zdy + wd[i].direction.y * coeffect;		//Tangent (0,1,zdy)
	}
	height[3 * offset + 2] = z;
	normal[3 * offset] = -zdx;
	normal[3 * offset + 1] = -zdy;
	normal[3 * offset + 2] = 1;

}


extern "C" void WavesUpdate(float time, int size, int numWaves, cudaGraphicsResource* cudaVBO, cudaGraphicsResource* cudaNor, WavesData* wd)
{
	float* devBuff;
	size_t sized;

	float* norBuff;
	size_t sizen;
 
	WavesData* gpudata;

	dim3 threadsPerBlock(16, 16);
	dim3 numBlocks((size - 1) / threadsPerBlock.x + 1, (size - 1) / threadsPerBlock.y + 1);

	if (cudaGraphicsMapResources(1, &cudaVBO, 0) != cudaSuccess)
		printf("Failed\n");
	if (cudaGraphicsMapResources(1, &cudaNor, 0) != cudaSuccess)
		printf("Failed\n");


	cudaMalloc((void**)&gpudata, sizeof(WavesData)* numWaves);
	cudaMemcpy(gpudata, wd, sizeof(WavesData)* numWaves, cudaMemcpyHostToDevice);

	cudaGraphicsResourceGetMappedPointer((void**)&devBuff, &sized, cudaVBO);
	cudaGraphicsResourceGetMappedPointer((void**)&norBuff, &sizen, cudaNor);


	WavesCubaUpdate << <numBlocks, threadsPerBlock >> >(devBuff, norBuff, time, size, numWaves, gpudata);

	if (cudaGraphicsUnmapResources(1, &cudaVBO, 0) != cudaSuccess)
		printf("Failed\n");
	if (cudaGraphicsUnmapResources(1, &cudaNor, 0) != cudaSuccess)
		printf("Failed\n");
	cudaFree(gpudata);
}


	//float hx = 0;
	//float hy = 0;
	//float hz = 0;
	//for (int i = 0; i < numWaves; i++)
	//{
	//	float a = wd[i].amplitude;
	//	float dx = wd[i].direction.x;
	//	float dy = wd[i].direction.y;
	//	float l = wd[i].waveLength;
	//	float w = 2 * PI / l;
	//	float thyta = wd[i].speed * time * w;
	//	float k = 2.f;
	//	float q = k / (w*a*numWaves);

	//	float sinax = sin(w*(dx*cx + dy*cy) + thyta);
	//	float cosax = cos(w*(dx*cx + dy*cy) + thyta);

	//	hx = hx + q*a*dx*cosax;
	//	hy = hy + q*a*dy*cosax;
	//	hz = a*sinax;
	//}
	//height[3 * offset] = hx + cx;
	//height[3 * offset + 1] = hy + cy;
	//height[3 * offset + 2] = hz;